#include "avcodec.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "x264/common/bs.h"

typedef struct TAVSContext {
	int test;
	FILE tavs_stat;
	struct {
		int i_nal;
		//x264_nal_t  nal[X264_NAL_MAX];
		int i_bitstream; /* size of p_bitstream */
		uint8_t *p_bitstream; /* will hold data for all nal */
		bs_t bs;
	} out;

	struct {
		float snr_y; //!< current Y SNR
		float snr_u; //!< current U SNR
		float snr_v; //!< current V SNR
		float snr_y1; //!< SNR Y(dB) first frame
		float snr_u1; //!< SNR U(dB) first frame
		float snr_v1; //!< SNR V(dB) first frame
		float snr_ya; //!< Average SNR Y(dB) remaining frames
		float snr_ua; //!< Average SNR U(dB) remaining frames
		float snr_va; //!< Average SNR V(dB) remaining frames
	} SNRParameters;

	//! all input parameters
	struct {
		//---------------------prerequisite------------------
		//seq header
		int profile_id;
		int level_id;
		int progressive_frame;
		int img_width; //!< GH: if CUSTOM image format is chosen, use this size
		int img_height; //!< GH: width and height must be a multiple of 16 pels
		int chroma_format;
		int sample_precision;
		int aspect_ratio_information;
		int frame_rate_code;//xfwang  2004.7.28
		int bit_rate_lower;
		int bit_rate_upper;
		int low_delay;
		int bbv_buffer_size;


		//------------------------other------------------------
//
//		int no_frames; //!< number of frames to be encoded
//		int qp0; //!< QP of first frame
//		int qpN; //!< QP of remaining frames
//		int jumpd; //!< number of frames to skip in input sequence (e.g 2 takes frame 0,3,6,9...)
//		int hadamard; /*!< 0: 'normal' SAD in 1/3 pixel search.  1: use 4x4 Haphazard transform and '
//		 Sum of absolute transform difference' in 1/3 pixel search                   */
//		int search_range; /*!< search range - integer pel search and 16x16 blocks.  The search window is
//		 generally around the predicted vector. Max vector is 2xmcrange.  For 8x8
//		 and 4x4 block sizes the search range is 1/2 of that for 16x16 blocks.       */
//		int no_multpred; /*!< 1: prediction from the last frame only. 2: prediction from the last or
//		 second last frame etc.  Maximum 5 frames                                    */
//
//		int yuv_format; //!< GH: YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4,currently only 4:2:0 is supported)
//		int color_depth; //!< GH: YUV color depth per component in bit/pel (currently only 8 bit/pel is supported)
//		int intra_upd; /*!< For error robustness. 0: no special action. 1: One GOB/frame is intra coded
//		 as regular 'update'. 2: One GOB every 2 frames is intra coded etc.
//		 In connection with this intra update, restrictions is put on motion vectors
//		 to prevent errors to propagate from the past                                */
//		int blc_size[8][2]; //!< array for different block sizes
//		int infile_header; //!< If input file has a header set this to the length of the header
//		char infile[100]; //!< YUV 4:2:0 input format
//		char outfile[100]; //!< AVS compressed output bitstream
//		char ReconFile[100]; //!< Reconstructed Pictures
//		char TraceFile[100]; //!< Trace Outputs
//		int intra_period;
//		// B pictures
//		int successive_Bframe; //!< number of B frames that will be used
//		int qpB; //!< QP of B frames
//		int SequenceHeaderType;
//		int InterSearch16x16;
//		int InterSearch16x8;
//		int InterSearch8x16;
//		int InterSearch8x8;
//		/*dingo
//		char PictureTypeSequence[MAXPICTURETYPESEQUENCELEN];
//		*/
//		int rdopt;
//		int InterlaceCodingOption;
//		//AVS
//		//int bit_rate;
//		int slice_weighting_flag;
//		int mb_weighting_flag;
//		int vec_period;
//		int seqheader_period; // Random Access period though sequence header
//		int video_format;
//		int color_description;
//		int color_primaries;
//		int transfer_characteristics;
//		int matrix_coefficients;
//		int hour;
//		int minute;
//		int second;
//		int frame_offset;
//		int progressive_sequence;
//		int repeat_first_field;
//		int top_field_first;
//		int video_range;
//		int stream_length_flag;
//		int picture_decoder_order_flag;
//		int frame_pred_frame_dct;
//		int fixed_picture_qp;
//		int time_code_flag;
//		int display_horizontal_size;
//		int display_vertical_size;
//		int dct_adaptive_flag;
//		//  int slice_enable;
//		int slice_parameter;
//		int slice_row_nr;
//		int skip_mode_flag;
//		int loop_filter_disable;
//		int loop_filter_parameter_flag;
//		int alpha_c_offset;
//		int beta_offset;
//		//! Rate Control on AVS standard
//		int RCEnable;
//		int bit_rate;
//		int SeinitialQP;
//		int basicunit;
//		int channel_type;
//		int frame_rate;
//		int stuff_height;
	} InputParameters;

	//! ImageParameters
	 struct {
		int number; //!< current image number to be encoded
		int pn; //!< picture number
		int lindex; //!< next long term index to be used
		int max_lindex; //!< max long term index
		int nb_references;
		int current_mb_nr;
		int total_number_mb;
		int current_slice_nr;
		int type;
		int ptype;/*lgp*/
		int types; /*!< This is for SP-Pictures, since all the syntax elements for SP-Pictures
		 are the same as P-pictures, we keep the img->type as P_IMG but indicate
		 SP-Pictures by img->types */
		int no_multpred; /*!< 1: prediction from the last frame only.
		 2: prediction from the last or second last frame etc. */
		int qp; //!< quant for the current frame
		int framerate;

		int width; //!< Number of pels
		int width_cr; //!< Number of pels chroma
		int height; //!< Number of lines
		int height_cr; //!< Number of lines  chroma
		int mb_y; //!< current MB vertical
		int mb_x; //!< current MB horizontal
		int block_y; //!< current block vertical
		int block_x; //!< current block horizontal
		int pix_y; //!< current pixel vertical
		int pix_x; //!< current pixel horizontal
		int pix_c_y; //!< current pixel chroma vertical
		int block_c_x; //!< current block chroma vertical
		int pix_c_x; //!< current pixel chroma horizontal
		int **ipredmode; //!< GH ipredmode[90][74];prediction mode for inter frames */ /* fix from ver 4.1
		int cod_counter; //!< Current count of number of skipped macroblocks in a row
		//int ****nz_coeff;            //!< number of coefficients per block (CAVLC)
		//int ****n_coeff_avs;         //!< number of coefficients per 8x8 block

		// some temporal buffers
		int mprr[9][16][16]; //!< all 9 prediction modes? // enlarged from 4 to 16 for ABT (is that neccessary?)

		int mprr_2[5][16][16]; //!< all 4 new intra prediction modes
		int mprr_c[2][4][8][8]; //!< new chroma 8x8 intra prediction modes
		int***** mv; //!< motion vectors for all block types and all reference frames
		int mpr[16][16]; //!< current best prediction mode
		int m7[16][16]; //!< the diff pixel values between orginal image and prediction

		int ****chromacofAC; /*lgp*///!< AC coefficients [uv][4x4block][level/run][scan_pos]
		int ****cofAC; //!< AC coefficients [8x8block][4x4block][level/run][scan_pos]
		int ***cofDC; //!< DC coefficients [yuv][level/run][scan_pos]
/*
		Macroblock *mb_data; //!< array containing all MBs of a whole frame
		// SyntaxElement   MB_SyntaxElements[MAX_SYMBOLS_PER_MB];    //!< temporal storage for all chosen syntax elements of one MB
		SyntaxElement *MB_SyntaxElements; //!< by oliver 0612
		*/
		int *quad; //!< Array containing square values,used for snr computation  */                                         /* Values are limited to 5000 for pixel differences over 70 (sqr(5000)).
		int **intra_block;

		int tr;
		int fld_type; //!< top or bottom field
		unsigned int fld_flag;
		int direct_intraP_ref[4][4];
		int imgtr_next_P_frm;
		int imgtr_last_P_frm;
		int imgtr_next_P_fld;
		int imgtr_last_P_fld;
		int imgtr_last_prev_P_frm;//Lou 1016
		// B pictures
		int b_interval;
		int p_interval;
		int b_frame_to_code;
		int fw_mb_mode;
		int bw_mb_mode;
		int***** p_fwMV; //!< for MVDFW
		int***** p_bwMV; //!< for MVDBW

		int***** all_mv; //!< replaces local all_mv
		int***** all_bmv; //!< replaces local all_mv

		int num_ref_pic_active_fwd_minus1;
		int num_ref_pic_active_bwd_minus1;

		/*lgp*/
		int *****mv_fld;
		int *****p_fwMV_fld;
		int *****p_bwMV_fld;
		int *****all_mv_fld;
		int *****all_bmv_fld;

		int field_mb_y; // Macroblock number of a field MB
		int field_block_y; // Vertical block number for the first block of a field MB
		int field_pix_y; // Co-ordinates of current macroblock in terms of field pixels (luma)
		int field_pix_c_y; // Co-ordinates of current macroblock in terms of field pixels (chroma)
		int *****mv_top; //!< For MB level field/frame coding tools
		int *****mv_bot; //!< For MB level field/frame coding tools
		int *****p_fwMV_top; //!< For MB level field/frame coding tools
		int *****p_fwMV_bot; //!< For MB level field/frame coding tools
		int *****p_bwMV_top; //!< For MB level field/frame coding tools
		int *****p_bwMV_bot; //!< For MB level field/frame coding tools
		int *****all_mv_top; //!< For MB level field/frame coding tools
		int *****all_mv_bot; //!< For MB level field/frame coding tools
		int *****all_bmv_top; //!< For MB level field/frame coding tools
		int *****all_bmv_bot; //!< For MB level field/frame coding tools
		int **ipredmode_top; //!< For MB level field/frame coding tools
		int **ipredmode_bot; //!< For MB level field/frame coding tools
		int field_mode; //!< For MB level field/frame -- field mode on flag
		int top_field; //!< For MB level field/frame -- top field flag
		int auto_crop_right;
		int auto_crop_bottom;
		int buf_cycle;

		unsigned int frame_num; //frame_num for this frame

		//the following are sent in the slice header
		int NoResidueDirect;

		int coding_stage;/*lgp*/
		int block8_x;/*lgp*/
		int block8_y;/*lgp*/
		int coded_mb_nr;

		int***** omv;
		int***** all_omv; //!< replaces local all_mv
		int***** omv_fld;
		int***** all_omv_fld; //!< replaces local all_mv

		int current_slice_start_mb;
		int current_slice_qp;
		int progressive_frame;
		int picture_structure;
		int dropflag;
		int advanced_pred_mode_disable;
		int old_type;
		int current_mb_nr_fld;

		// !! for weighting prediction
		int LumVarFlag;
		int lum_scale[4];
		int lum_shift[4];
		int chroma_scale[4];
		int chroma_shift[4];
		int mb_weighting_flag; //0 all MB in one frame should be weighted, 1 use the mb_weight_flag
		int weighting_prediction;
		int mpr_weight[16][16];
		int top_bot; // -1: frame / 0: top field / 1: bottom field / Yulj 2004.07.14
		int mb_no_currSliceLastMB; // the last MB no in current slice.      Yulj 2004.07.15


		/*rate control*/
		int NumberofHeaderBits;
		int NumberofTextureBits;
		int NumberofBasicUnitHeaderBits;
		int NumberofBasicUnitTextureBits;
		double TotalMADBasicUnit;
		int NumberofMBTextureBits;
		int NumberofMBHeaderBits;
		int NumberofCodedBFrame;
		int NumberofCodedPFrame;
		int NumberofGOP;
		int TotalQpforPPicture;
		int NumberofPPicture;
		double MADofMB[10000];
		int BasicUnitQP;
		int TopFieldFlag;
		int FieldControl;
		int FieldFrame;
		int Frame_Total_Number_MB;
		int IFLAG;
		int NumberofCodedMacroBlocks;
		int BasicUnit;
		int bot_MB;
		//	int VEC_FLAG;			    // Commented by cjw, 20070327
		int Seqheader_flag; // Added by cjw, 20070327
		int curr_picture_distance; // Added by Xiaozhen Zheng, 20070405
		int last_picture_distance; // Added by Xiaozhen Zheng, 20070405
		int count;
		int count_PAFF;
	} ImageParameters;
} TAVSContext;

//------------------------------------------------------------------
///////////////////bitstream.c//////////////////////////////////////
//rewrite from RM5.2
int WriteSequenceHeader(bs_t *bs, TAVSContext *x4){
	//seqence start code
	//bitscount+=u_v(32,"seqence start code",0x1b0,bitstream);
	bs_write(bs,32,0x1b0);

	//profile_id
	//bitscount+=u_v(8,"profile_id",input->profile_id,bitstream);
	bs_write(bs,8,x4->InputParameters.profile_id);
	//level_id
	//bitscount+=u_v(8,"level_id",input->level_id,bitstream);
	bs_write(bs,8,x4->InputParameters.level_id);
	//progressive_sequence
	//bitscount+=u_v(1,"progressive_sequence",input->progressive_frame,bitstream); //add by wuzhongmou 0610
	bs_write(bs,1,x4->InputParameters.progressive_frame);
	//picture width
	//bitscount+=u_v(14,"picture width",img->width,bitstream); //add by wuzhongmou 0610
	bs_write(bs,14,x4->InputParameters.img_width);
	//picture height
	//bitscount+=u_v(14,"picture height",img->height,bitstream); //add by wuzhongmou 0610
	bs_write(bs,14,x4->InputParameters.img_height);
	//chroma foramt
	//bitscount+=u_v(2,"chroma foramt",input->chroma_format,bitstream);
	bs_write(bs,2,x4->InputParameters.chroma_format);
	//sample precision
	//bitscount+=u_v(3,"sample precision",input->sample_precision,bitstream);
	bs_write(bs,3,x4->InputParameters.sample_precision);
	//aspect ratio information
	//bitscount+=u_v(4,"aspect ratio information",input->aspect_ratio_information,bitstream);
	bs_write(bs,4,x4->InputParameters.aspect_ratio_information);
	//frame rate code
	//bitscount+=u_v(4,"frame rate code",input->frame_rate_code,bitstream);
	bs_write(bs,4,x4->InputParameters.frame_rate_code);

	//input->bit_rate_lower = input->bit_rate_upper = 0;
	//bit rate lower
	//bitscount+=u_v(18,"bit rate lower",input->bit_rate_lower,bitstream);
	bs_write(bs,18,x4->InputParameters.bit_rate_lower);
	//marker bit
	//bitscount+=u_v(1,"marker bit",1,bitstream);
	bs_write(bs,1,1);
	//bit rate upper
	//bitscount+=u_v(12,"bit rate upper",input->bit_rate_upper,bitstream);
	bs_write(bs,12,x4->InputParameters.bit_rate_upper);
	//low delay
	//bitscount+=u_v(1,"low delay",input->low_delay,bitstream);
	bs_write(bs,1,x4->InputParameters.low_delay);
	//marker bit
	//bitscount+=u_v(1,"marker bit",1,bitstream);
	bs_write(bs,1,1);
	//bbv buffer size
	//bitscount+=u_v(18,"bbv buffer size",input->bbv_buffer_size,bitstream);
	bs_write(bs,18,x4->InputParameters.bbv_buffer_size);
	//reserved bits
	//bitscount+=u_v(3,"reserved bits",0,bitstream);
	bs_write(bs,3,0);
	bs_align_0(bs);

	return 0;
}

int WriteSequenceDisplayExtension();

int WriteCopyrightExtension();

int WriteCameraParametersExtension();

int WriteUserData();

int WriteVideoEditCode();

int WriteSliceHeader();

int IPictureHeader(bs_t *bs, TAVSContext *x4)
{
//	Bitstream *bitstream = currBitStream;
//	int len = 0;
//	int tc;
//	int time_code_flag;
//	marker_bit=1;
//	time_code_flag = 0;
//
//	len += u_v(32, "I picture start code",0x1B3,bitstream);

	bs_write(bs,32,0x1B3);
	//TODO fixit
  //rate control
//	if(input->RCEnable&&img->BasicUnit<=img->Frame_Total_Number_MB)
//		input->fixed_picture_qp = 0;//  [5/8/2007 Leeswan]
//	else
//		input->fixed_picture_qp = 1;


	//xyji 12.23
//	len+=u_v(16,"bbv delay",0xffff/*img->bbv_delay*/,bitstream);
	bs_write(bs,16,0xffff);
//	len += u_v(1, "time_code_flag",0,bitstream);
	bs_write(bs,1,0);
	//TODO fixit
	//if (time_code_flag)
	//if(0)
//	{
//		tc = frametotc(tc0+frame,img->dropflag);
//		len += u_v(24, "time_code",tc,bitstream);
//	}

	//len+=u_1("marker_bit",1,bitstream);  //add by wuzhongmou 0610
	bs_write(bs,1,1);

//	len+=u_v(8,"picture_distance",picture_distance,bitstream);
	//TODO write picture distance
	bs_write(bs,8,0x11);
	//TODO Fix it
//	if(input->low_delay)
//	{
//		len+=ue_v("bbv check times",bbv_check_times,bitstream);
//	}

//	len+=u_v(1,"progressive frame",img->progressive_frame,bitstream);
//	if(!img->progressive_frame)
//		len+=u_v(1,"picture_structure",img->picture_structure,bitstream);

//	len+=u_v(1,"top field first",input->top_field_first,bitstream);
//	len+=u_v(1,"repeat first field",input->repeat_first_field,bitstream);
//    len+=u_v(1,"fixed picture qp",input->fixed_picture_qp,bitstream);
	//rate control
//	if(input->RCEnable)
//		len+=u_v(6,"I picture QP",img->qp,bitstream);
//	else
//	{
//		len+=u_v(6,"I picture QP",input->qp0,bitstream);
//		img->qp = input->qp0;
//	}

	//xyji 12.23
//	if(img->progressive_frame==0)   //by oliver according to 1658
//		if(img->picture_structure == 0)
//		{
//			len+=u_v(1,"skip mode flag",input->skip_mode_flag,bitstream);
//		}
//
//	len+=u_v(4,"reserved bits",0,bitstream);
//
//	len+=u_v(1,"loop filter disable",input->loop_filter_disable,bitstream);
//	if (!input->loop_filter_disable)
//	{
//		len+=u_v(1,"loop filter parameter flag",input->loop_filter_parameter_flag,bitstream);
//		if (input->loop_filter_parameter_flag)
//		{
//			len+=se_v("alpha offset",input->alpha_c_offset,bitstream);
//			len+=se_v("beta offset",input->beta_offset,bitstream);
//		}
//	}

//	picture_reference_flag  = 0;

//	return len;
		return 1;
}
//------------------------------------------------------------------------------------

extern int tavs_encode_init(AVCodecContext *avctx) {

	TAVSContext *x4 = avctx->priv_data;

	//init TAVSContext
	x4->out.i_bitstream = 10000;
	x4->out.p_bitstream = av_malloc(x4->out.i_bitstream * sizeof(uint8_t));

	bs_init(&x4->out.bs, x4->out.p_bitstream, x4->out.i_bitstream);

	//init FuncTables

	//init SequenceStart





//OTHER
	//x4->out.bs;
	//av_log(NULL, AV_LOG_DEBUG, "tavs_init\n");
	//fprintf(stdout,"test");
	//init_vlc();
	return 0;
}

extern int tavs_encode_frame(AVCodecContext *ctx, uint8_t *buf, int bufsize,
		void *data) {


	TAVSContext *x4 = ctx->priv_data;
	AVFrame *frame = data;

	ctx->frame_number++;
	WriteSequenceHeader(&x4->out.bs, x4);

	bs_write(&x4->out.bs, 8, 0xa);

	bs_write(&x4->out.bs, 8, 0xba);

	bs_write(&x4->out.bs, 8, 0xab);
	bs_write(&x4->out.bs, 32, 0x1b);
	//	init_put_bits(init_x4->s,buf,20);

	//	init_x4->s
	//uint8_t *temp = av_malloc(sizeof(char) * 100);
	//  for(i = 0; i < 3; i++){
	//      x4->pic.img.plane[i] = frame->data[i];
	//      x4->pic.img.i_stride[i] = frame->linesize[i];
	//  }


	//	av_log(NULL, AV_LOG_DEBUG,"tavs_frame\n");
	x4->test++;
	//	temp = "a";
	//buf = x4->out.bs.p_start;
	memcpy(buf, x4->out.bs.p_start, x4->out.bs.p- x4->out.bs.p_start);
	/*
	*buf = frame->linesize[0];
	*(buf + 1) = frame->linesize[1];
	*(buf + 2) = frame->linesize[2];
	*(buf + 3) = frame->linesize[3];
	*(buf */
	return (x4->out.bs.p- x4->out.bs.p_start);
}

static int tavs_encode_close(AVCodecContext *avctx) {
	//fprintf("x264_end\n");
	av_log(NULL, AV_LOG_DEBUG, "t\n");
	TAVSContext *x4 = avctx->priv_data;

	x4->test++;
	return 0;
}

AVCodec tavs_encoder = { .name = "cavs", .type = CODEC_TYPE_VIDEO,
		.id = CODEC_ID_CAVS, .priv_data_size = sizeof(TAVSContext), .init = tavs_encode_init,
		.encode = tavs_encode_frame, .close = tavs_encode_close, .pix_fmts = (enum PixelFormat[]) {PIX_FMT_YUV420P, -1} };
